#include "iConfig.hpp"

#if GLF_ENABLE_DEBUGGER

#include <glf/debugger/macros.h>
#include <glf/app.h>

#include <glf/io/fileStream.h>

namespace glf
{
namespace debugger
{
	Macros::Macros() 
		:	Module("MACRO")
		,	mCurrentMacro(0)
	{
	
	}

	GLF_DEFINE_SINGLETON_WITH_DEP(Macros, Debugger)

	Macros::~Macros()
	{
        if( glf::debugger::Debugger::GetInstance() )
        {
		    glf::debugger::Debugger::GetInstance()->UnregisterModule( this );
        }
		for(size_t i = 0; i < mMacros.size(); ++i) {
			delete mMacros[i];
		}
		mMacros.clear();
	}

	void Macros::UpdateFrame()
	{
		if(GetDebugger()->IsConnected())
		{
			//static int frame = 0;
			//
			//if(frame++ == 60*5) {
			//	frame = 0;
			//	mCommand = EC_LIST_MACROS;
			//}
			//
			////find a better way to send macros list
			//if(mCommand == EC_LIST_MACROS) {


			//	mCommand = EC_NONE;
			//}

			if(mCurrentMacro && mCurrentMacro->IsPlaying()) {
				PacketWriter& pw = GetPacketWriter();

				pw.Init(SEND_PROGRESS);
				pw.Write((int)mCurrentMacro->GetProgress());
				pw.Write((int)mCurrentMacro->GetDuration());
				
				Send(pw);
			}
		}
	}

	void Macros::Parse(int type, PacketReader& in)
	{
		switch(type)
		{
		case TELL_AVAILABLE_MACROS:
		{	
			fs::DirHandle dh;
			std::vector<stringc> macros;

			if(dh.FindFirst("macros", ios::loc_home|ios::list_all)) {
				do {
					stringc path = dh.fileInfo.filename;
					if(path.rfind(".macro") != std::string::npos)
						macros.push_back(path);
				} while(dh.FindNext());
			}
			
			PacketWriter& pw = GetPacketWriter();

			pw.Init(AVAILABLE_MACROS);
			pw.Write((uint)macros.size());
			for(size_t i = 0; i <macros.size(); ++i) {
				pw.Write(macros[i].c_str());
			}
			Send(pw);

		}	break;
		case SENDLIST:
		{
			for(size_t i = 0; i < mMacros.size(); ++i) {
				delete mMacros[i];
			}
			mMacros.resize(in.ReadIntLE());
			for(size_t i = 0; i < mMacros.size(); ++i) {
				mMacros[i] = new Macro(GetAppEventMgr(), in);
				mMacros[i]->AddCallback(MacroCallback, this);
			}
		}	break;
		case PLAY: 
		{
			size_t index = in.ReadIntLE();
			
			if(index < mMacros.size()) {
				mCurrentMacro = mMacros[index];
				mCurrentMacro->StartPlaying();
			}

		} break;
		case PAUSE:
		{	
			if(mCurrentMacro)
				mCurrentMacro->Pause();
		}	break;
        case STOP:
		{
			if(mCurrentMacro) {
				if(mCurrentMacro->IsRecording()) {
					mCurrentMacro->StopRecording();
					
					if(mCurrentMacro->IsLocal()) {
						mCurrentMacro->Save();
					} else {
						PacketWriter& pw = GetPacketWriter();
						pw.Init(SAVE);
						mCurrentMacro->Save(pw);
						Send(pw);
					}
				} else if(mCurrentMacro->IsPlaying() || mCurrentMacro->IsPaused()) {
					mCurrentMacro->StopPlaying();
				}
			}
		}	break;
        case RECORD:
		{	
			size_t index = in.ReadIntLE();
			
			if(index < mMacros.size()) {
				mCurrentMacro = mMacros[index];
				mCurrentMacro->ClearEvents();
				mCurrentMacro->AddEventsToRecord(glf::IET_INPUT_START, glf::IET_INPUT_END);
				mCurrentMacro->StartRecording();
			}
		}	break;
		case SELECT:
		{
			size_t index = in.ReadIntLE();

			if(!mCurrentMacro || mCurrentMacro->IsDisabled()) {
				if(index < mMacros.size()) {
					mCurrentMacro = mMacros[index];
				}
			}
		} break;
 		}
	}

	void Macros::MacroCallback(Macro* macro, Macro::EventType et, void* param) {

		if(mCurrentMacro == macro) {
			if(et == Macro::EET_PLAYBACKENDED) {
				PacketWriter& pw = GetPacketWriter();

				pw.Init(END_OF_MACRO);

				Send(pw);
			}
		}
	}

} //namespace debugger
} //namespace glf

#endif // GLF_ENABLE_DEBUGGER
